<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN">
<head>
  <title></title>
  <link href="../Styles/stylesheet.css" rel="stylesheet" type="text/css" />
  
<style type="text/css">
@page { margin-bottom: 5.000000pt; margin-top: 5.000000pt; }
</style>
</head>

<body>
  <h2><span style="border-bottom:1px solid">Chapter_21</span></h2>

  <p>ocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>List</p>

  <p>ActionEvent, FocusEvent, KeyEvent, MouseEvent, ItemEvent, ComponentEvent</p>

  <p>Menu</p>

  <p>ActionEvent</p>

  <p>MenuItem</p>

  <p>ActionEvent</p>

  <p>Panel</p>

  <p>ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>PopupMenu</p>

  <p>ActionEvent</p>

  <p>Scrollbar</p>

  <p>AdjustmentEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>ScrollPane</p>

  <p>ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>TextArea</p>

  <p>TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>TextComponent</p>

  <p>TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>TextField</p>

  <p>ActionEvent, TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent</p>

  <p>Window</p>

  <p>ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent一旦知道了一个特定的组件支持哪些事件，就不必再去寻找任何东西来响应那个事件。只需简单地：</p>

  <p>(1) 取得事件类的名字，并删掉其中的“Event”字样。在剩下的部分加入“Listener”字样。这就是在我们的内部类里需要实现的接收器接口。</p>

  <p>(2) 实现上面的接口，针对想要捕获的事件编写方法代码。例如，假设我们想捕获鼠标的移动，所以需要为MouseMotiionListener接口的mouseMoved()方法编写代（当然还必须实现其他一些方法，但这里有捷径可循，马上就会讲到这个问题）。</p>

  <p>(3) 为步骤2中的接收器类创建一个对象。随自己的组件和方法完成对它的注册，方法是在接收器的名字里加入一个前缀“add”。比如addMouseMotionListener()。</p>

  <p>下表是对接收器接口的一个总结：</p>

  <p>接收器接口 接口中的方法</p>

  <p>Listener interface</p>

  <p>w/ adapter</p>

  <p>Methods in interface</p>

  <p>ActionListener</p>

  <p>actionPerformed(ActionEvent)</p>

  <p>AdjustmentListener</p>

  <p>adjustmentValueChanged(</p>

  <p>AdjustmentEvent)</p>

  <p>ComponentListener</p>

  <p>ComponentAdapter</p>

  <p>componentHidden(ComponentEvent)</p>

  <p>componentShown(ComponentEvent)</p>

  <p>componentMoved(ComponentEvent)</p>

  <p>componentResized(ComponentEvent)</p>

  <p>ContainerListener</p>

  <p>ContainerAdapter</p>

  <p>componentAdded(ContainerEvent)</p>

  <p>componentRemoved(ContainerEvent)</p>

  <p>FocusListener</p>

  <p>FocusAdapter</p>

  <p>focusGained(FocusEvent)</p>

  <p>focusLost(FocusEvent)</p>

  <p>KeyListener</p>

  <p>KeyAdapter</p>

  <p>keyPressed(KeyEvent)</p>

  <p>keyReleased(KeyEvent)</p>

  <p>keyTyped(KeyEvent)</p>

  <p>MouseListener</p>

  <p>MouseAdapter</p>

  <p>mouseClicked(MouseEvent)</p>

  <p>mouseEntered(MouseEvent)</p>

  <p>mouseExited(MouseEvent)</p>

  <p>mousePressed(MouseEvent)</p>

  <p>mouseReleased(MouseEvent)</p>

  <p>MouseMotionListener</p>

  <p>MouseMotionAdapter</p>

  <p>mouseDragged(MouseEvent)</p>

  <p>mouseMoved(MouseEvent)</p>

  <p>WindowListener</p>

  <p>WindowAdapter</p>

  <p>windowOpened(WindowEvent)</p>

  <p>windowClosing(WindowEvent)</p>

  <p>windowClosed(WindowEvent)</p>

  <p>windowActivated(WindowEvent)</p>

  <p>windowDeactivated(WindowEvent)</p>

  <p>windowIconified(WindowEvent)</p>

  <p>windowDeiconified(WindowEvent)</p>

  <p>ItemListener</p>

  <p>itemStateChanged(ItemEvent)</p>

  <p>TextListener</p>

  <p>textValueChanged(TextEvent)1. 用接收器适配器简化操作</p>

  <p>在上面的表格中，我们可以注意到一些接收器接口只有唯一的一个方法。它们的执行是无轻重的，因为我们仅当需要书写特殊方法时才会执行它们。然而，接收器接口拥有多个方法，使用起来却不太友好。例如，我们必须一直运行某些事物，当我们创建一个应用程序时对帧提供一个WindowListener，以便当我们得到windowClosing()事件时可以调用System.exit(0)以退出应用程序。但因为WindowListener是一个接口，我们必须执行其它所有的方法即使它们不运行任何事件。这真令人讨厌。</p>

  <p>为了解决这个问题，每个拥有超过一个方法的接收器接口都可拥有适配器，它们的名我们可以在上面的表格中看到。每个适配器为每个接口方法提供默认的方法。（WindowAdapter的默认方法不是windowClosing()，而是System.exit(0)方法。）此外我们所要做的就是从适配器处继承并过载唯一的需要变更的方法。例如，典型的WindowListener我们会像下面这样的使用。</p>

  <p>class MyWindowListener extends WindowAdapter {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>}</p>

  <p>适配器的全部宗旨就是使接收器的创建变得更加简便。</p>

  <p>但所谓的“适配器”也有一个缺点，而且较难发觉。假定我们象上面那样写一个WindowAdapter：</p>

  <p>class MyWindowListener extends WindowAdapter {</p>

  <p>public void WindowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>}</p>

  <p>表面上一切正常，但实际没有任何效果。每个事件的编译和运行都很正常――只是关闭窗口不会退出程序。您注意到问题在哪里吗？在方法的名字里：是WindowClosing()，而不是windowClosing()。大小写的一个简单失误就会造成一个崭新的方法。但是，这并非我们关闭窗口时调用的方法，所以当然没有任何效果。</p>

  <p>13.16.3 用Java 1.1 AWT制作窗口和程序片</p>

  <p>我们经常都需要创建一个类，使其既可作为一个窗口调用，亦可作为一个程序片调用。为做到这一点，只需为程序片简单地加入一个main()即可，令其在一个Frame（帧）里构建程序片的一个实例。作为一个简单的示例，下面让我们来看看如何对Button2New.java作一番修改，使其能同时作为应用程序和程序片使用：</p>

  <p>//: Button2NewB.java</p>

  <p>// An application and an applet</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*; // Must add this</p>

  <p>import java.applet.*;</p>

  <p>public class Button2NewB extends Applet {</p>

  <p>Button</p>

  <p>b1 = new Button("Button 1"),</p>

  <p>b2 = new Button("Button 2");</p>

  <p>TextField t = new TextField(20);</p>

  <p>public void init() {</p>

  <p>b1.addActionListener(new B1());</p>

  <p>b2.addActionListener(new B2());</p>

  <p>add(b1);</p>

  <p>add(b2);</p>

  <p>add(t);</p>

  <p>}</p>

  <p>class B1 implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t.setText("Button 1");</p>

  <p>}</p>

  <p>}</p>

  <p>class B2 implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t.setText("Button 2");</p>

  <p>}</p>

  <p>}</p>

  <p>// To close the application:</p>

  <p>static class WL extends WindowAdapter {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>}</p>

  <p>// A main() for the application:</p>

  <p>public static void main(String[] args) {</p>

  <p>Button2NewB applet = new Button2NewB();</p>

  <p>Frame aFrame = new Frame("Button2NewB");</p>

  <p>aFrame.addWindowListener(new WL());</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(300,200);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>内部类WL和main()方法是加入程序片的唯一两个元素，程序片剩余的部分则原封未动。事实上，我们通常将WL类和main()方法做一结小的改进复制和粘贴到我们自己的程序片里（请记住创建内部类时通常需要一个外部类来处理它，形成它静态地消除这个需要）。我们可以看到在main()方法里，程序片明确地初始化和开始，因为在这个例子里浏览器不能为我们有效地运行它。当然，这不会提供全部的浏览器调用stop()和destroy()的行为，但对大多数的情况而言它都是可接受的。如果它变成一个麻烦，我们可以：</p>

  <p>(1) 使程序片句柄为一个静态类（以代替局部可变的main()），然后：</p>

  <p>(2) 在我们调用System.exit()之前在WindowAdapter.windowClosing()中调用applet.stop()和applet.destroy()。</p>

  <p>注意最后一行：</p>

  <p>aFrame.setVisible(true);</p>

  <p>这是Java 1.1 AWT的一个改变。show()方法不再被支持，而setVisible(true)则取代了show()方法。当我们在本章后面部分学习Java Beans时，这些表面上易于改变的方法将会变得更加的合理。</p>

  <p>这个例子同样被使用TextField修改而不是显示到控制台或浏览器状态行上。在开发程序时有一个限制条件就是程序片和应用程序我们都必须根据它们的运行情况选择输入和输出结构。</p>

  <p>这里展示了Java 1.1 AWT的其它小的新功能。我们不再需要去使用有错误倾向的利用字符串指定BorderLayout定位的方法。当我们增加一个元素到Java 1.1版的BorderLayout中时，我们可以这样写：</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>我们对位置规定一个BorderLayout的常数，以使它能在编译时被检验（而不是对老的结构悄悄地做不合适的事）。这是一个显著的改善，并且将在这本书的余下部分大量地使用。</p>

  <p>2. 将窗口接收器变成匿名类</p>

  <p>任何一个接收器类都可作为一个匿名类执行，但这一直有个意外，那就是我们可能需要在其它场合使用它们的功能。但是，窗口接收器在这里仅作为关闭应用程序窗口来使用，因此我们可以安全地制造一个匿名类。然后，main()中的下面这行代码：</p>

  <p>aFrame.addWindowListener(new WL());</p>

  <p>会变成：</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>这有一个优点就是它不需要其它的类名。我们必须对自己判断是否它使代码变得易于理解或者更难。不过，对本书余下部分而言，匿名内部类将通常被使用在窗口接收器中。</p>

  <p>3. 将程序片封装到JAR文件里</p>

  <p>一个重要的JAR应用就是完善程序片的装载。在Java 1.0版中，人们倾向于试法将它们的代码填入到单个的程序片类里，因此客户只需要单个的服务器就可适合下载程序片代码。但这不仅使结果凌乱，难以阅读（当然维护也然）程序，但类文件一直不能压缩，因此下载从来没有快过。</p>

  <p>JAR文件将我们所有的被压缩的类文件打包到一个单个儿的文件中，再被浏览器下载。现在我们不需要创建一个糟糕的设计以最小化我们创建的类，并且用户将得到更快地下载速度。</p>

  <p>仔细想想上面的例子，这个例子看起来像Button2NewB，是一个单类，但事实上它包含三个内部类，因此共有四个。每当我们编译程序，我会用这行代码打包它到一个JAR文件：</p>

  <p>jar cf Button2NewB.jar *.class</p>

  <p>这是假定只有一个类文件在当前目录中，其中之一来自Button2NewB.java（否则我们会得到特别的打包）。</p>

  <p>现在我们可以创建一个使用新文件标签来指定JAR文件的HTML页，如下所示：</p>

  <p>&lt;head&gt;&lt;title&gt;Button2NewB Example Applet</p>

  <p>&lt;/title&gt;&lt;/head&gt;</p>

  <p>&lt;body&gt;</p>

  <p>&lt;applet code="Button2NewB.class"</p>

  <p>archive="Button2NewB.jar"</p>

  <p>width=200 height=150&gt;</p>

  <p>&lt;/applet&gt;</p>

  <p>&lt;/body&gt;</p>

  <p>与HTML文件中的程序片标记有关的其他任何内容都保持不变。</p>

  <p>13.16.4 再研究一下以前的例子</p>

  <p>为注意到一些利用新事件模型的例子和为学习程序从老到新事件模型改变的方法，下面的例子回到在本章第一部分利用事件模型来证明的一些争议。另外，每个程序包括程序片和应用程序现在都可以借助或不借助浏览器来运行。</p>

  <p>1. 文本字段</p>

  <p>这个例子同TextField1.java相似，但它增加了显然额外的行为：</p>

  <p>//: TextNew.java</p>

  <p>// Text fields with Java 1.1 events</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>import java.applet.*;</p>

  <p>public class TextNew extends Applet {</p>

  <p>Button</p>

  <p>b1 = new Button("Get Text"),</p>

  <p>b2 = new Button("Set Text");</p>

  <p>TextField</p>

  <p>t1 = new TextField(30),</p>

  <p>t2 = new TextField(30),</p>

  <p>t3 = new TextField(30);</p>

  <p>String s = new String();</p>

  <p>public void init() {</p>

  <p>b1.addActionListener(new B1());</p>

  <p>b2.addActionListener(new B2());</p>

  <p>t1.addTextListener(new T1());</p>

  <p>t1.addActionListener(new T1A());</p>

  <p>t1.addKeyListener(new T1K());</p>

  <p>add(b1);</p>

  <p>add(b2);</p>

  <p>add(t1);</p>

  <p>add(t2);</p>

  <p>add(t3);</p>

  <p>}</p>

  <p>class T1 implements TextListener {</p>

  <p>public void textValueChanged(TextEvent e) {</p>

  <p>t2.setText(t1.getText());</p>

  <p>}</p>

  <p>}</p>

  <p>class T1A implements ActionListener {</p>

  <p>private int count = 0;</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t3.setText("t1 Action Event " + count++);</p>

  <p>}</p>

  <p>}</p>

  <p>class T1K extends KeyAdapter {</p>

  <p>public void keyTyped(KeyEvent e) {</p>

  <p>String ts = t1.getText();</p>

  <p>if(e.getKeyChar() ==</p>

  <p>KeyEvent.VK_BACK_SPACE) {</p>

  <p>// Ensure it's not empty:</p>

  <p>if( ts.length() &gt; 0) {</p>

  <p>ts = ts.substring(0, ts.length() - 1);</p>

  <p>t1.setText(ts);</p>

  <p>}</p>

  <p>}</p>

  <p>else</p>

  <p>t1.setText(</p>

  <p>t1.getText() +</p>

  <p>Character.toUpperCase(</p>

  <p>e.getKeyChar()));</p>

  <p>t1.setCaretPosition(</p>

  <p>t1.getText().length());</p>

  <p>// Stop regular character from appearing:</p>

  <p>e.consume();</p>

  <p>}</p>

  <p>}</p>

  <p>class B1 implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>s = t1.getSelectedText();</p>

  <p>if(s.length() == 0) s = t1.getText();</p>

  <p>t1.setEditable(true);</p>

  <p>}</p>

  <p>}</p>

  <p>class B2 implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t1.setText("Inserted by Button 2: " + s);</p>

  <p>t1.setEditable(false);</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>TextNew applet = new TextNew();</p>

  <p>Frame aFrame = new Frame("TextNew");</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(300,200);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>当TextField t1的动作接收器被激活时，TextField t3就是一个需要报告的场所。我们注意到仅当我们按下“enter”键时，动作接收器才会为“TextField”所激活。</p>

  <p>TextField t1附有几个接收器。T1接收器从t1复制所有文字到t2，强制所有字符串转换成大写。我们会发现这两个工作同是进行的，并且如果我们增加T1K接收器后我们再增加T1接收器，它就不那么重要：在文字字段内的所有的字符串将一直被强制变为大写。这看起来键盘事件一直在文字组件事件前被激活，并且如果我们需要保留t2的字符串原来输入时的样子，我们就必须做一些特别的工作。</p>

  <p>T1K有着其它的一些有趣的活动。我们必须测试backspace（因为我们现在控制着每一个事件）并执行删除。caret必须被明确地设置到字段的结尾；否则它不会像我们希望的运行。最后，为了防止原来的字符串被默认的机制所处理，事件必须利用为事件对象而存在的consume()方法所“耗尽”。这会通知系统停止激活其余特殊事件的事件处理器。</p>

  <p>这个例子同样无声地证明了设计内部类的带来的诸多优点。注意下面的内部类：</p>

  <p>class T1 implements TextListener {</p>

  <p>public void textValueChanged(TextEvent e) {</p>

  <p>t2.setText(t1.getText());</p>

  <p>}</p>

  <p>}</p>

  <p>t1和t2不属于T1的一部分，并且到目前为止它们都是很容易理解的，没有任何的特殊限制。这是因为一个内部类的对象能自动地捕捉一个句柄到外部的创建它的对象那里，因此我们可以处理封装类对象的方法和内容。正像我们看到的，这十分方便（注释⑥）。</p>

  <p>⑥：它也解决了“回调”的问题，不必为Java加入任何令人恼火的“方法指针”特性。</p>

  <p>2. 文本区域</p>

  <p>Java 1.1版中Text Area最重要的改变就滚动条。对于TextArea的构建器而言，我们可以立即控制TextArea是否会拥有滚动条：水平的，垂直的，两者都有或者都没有。这个例子更正了前面Java 1.0版TextArea1.java程序片，演示了Java 1.1版的滚动条构建器：</p>

  <p>//: TextAreaNew.java</p>

  <p>// Controlling scrollbars with the TextArea</p>

  <p>// component in Java 1.1</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>import java.applet.*;</p>

  <p>public class TextAreaNew extends Applet {</p>

  <p>Button b1 = new Button("Text Area 1");</p>

  <p>Button b2 = new Button("Text Area 2");</p>

  <p>Button b3 = new Button("Replace Text");</p>

  <p>Button b4 = new Button("Insert Text");</p>

  <p>TextArea t1 = new TextArea("t1", 1, 30);</p>

  <p>TextArea t2 = new TextArea("t2", 4, 30);</p>

  <p>TextArea t3 = new TextArea("t3", 1, 30,</p>

  <p>TextArea.SCROLLBARS_NONE);</p>

  <p>TextArea t4 = new TextArea("t4", 10, 10,</p>

  <p>TextArea.SCROLLBARS_VERTICAL_ONLY);</p>

  <p>TextArea t5 = new TextArea("t5", 4, 30,</p>

  <p>TextArea.SCROLLBARS_HORIZONTAL_ONLY);</p>

  <p>TextArea t6 = new TextArea("t6", 10, 10,</p>

  <p>TextArea.SCROLLBARS_BOTH);</p>

  <p>public void init() {</p>

  <p>b1.addActionListener(new B1L());</p>

  <p>add(b1);</p>

  <p>add(t1);</p>

  <p>b2.addActionListener(new B2L());</p>

  <p>add(b2);</p>

  <p>add(t2);</p>

  <p>b3.addActionListener(new B3L());</p>

  <p>add(b3);</p>

  <p>b4.addActionListener(new B4L());</p>

  <p>add(b4);</p>

  <p>add(t3); add(t4); add(t5); add(t6);</p>

  <p>}</p>

  <p>class B1L implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t5.append(t1.getText() + "\n");</p>

  <p>}</p>

  <p>}</p>

  <p>class B2L implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t2.setText("Inserted by Button 2");</p>

  <p>t2.append(": " + t1.getText());</p>

  <p>t5.append(t2.getText() + "\n");</p>

  <p>}</p>

  <p>}</p>

  <p>class B3L implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>String s = " Replacement ";</p>

  <p>t2.replaceRange(s, 3, 3 + s.length());</p>

  <p>}</p>

  <p>}</p>

  <p>class B4L implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t2.insert(" Inserted ", 10);</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>TextAreaNew applet = new TextAreaNew();</p>

  <p>Frame aFrame = new Frame("TextAreaNew");</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(300,725);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>我们发现只能在构造TextArea时能够控制滚动条。同样，即使TE AR没有滚动条，我们滚动光标也将被制止（可通过运行这个例子中验证这种行为）。</p>

  <p>3. 复选框和单选钮</p>

  <p>正如早先指出的那样，复选框和单选钮都是同一个类建立的。单选钮和复选框略有不同，它是复选框安置到CheckboxGroup中构成的。在其中任一种情况下，有趣的ItemEvent事件为我们创建一个ItemListener项目接收器。</p>

  <p>当处理一组复选框或者单选钮时，我们有一个不错的选择。我们可以创建一个新的内部类去为每个复选框处理事件，或者创建一个内部类判断哪个复选框被单击并注册一个内部类单独的对象为每个复选对象。下面的例子演示了两种方法：</p>

  <p>//: RadioCheckNew.java</p>

  <p>// Radio buttons and Check Boxes in Java 1.1</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>import java.applet.*;</p>

  <p>public class RadioCheckNew extends Applet {</p>

  <p>TextField t = new TextField(30);</p>

  <p>Checkbox[] cb = {</p>

  <p>new Checkbox("Check Box 1"),</p>

  <p>new Checkbox("Check Box 2"),</p>

  <p>new Checkbox("Check Box 3") };</p>

  <p>CheckboxGroup g = new CheckboxGroup();</p>

  <p>Checkbox</p>

  <p>cb4 = new Checkbox("four", g, false),</p>

  <p>cb5 = new Checkbox("five", g, true),</p>

  <p>cb6 = new Checkbox("six", g, false);</p>

  <p>public void init() {</p>

  <p>t.setEditable(false);</p>

  <p>add(t);</p>

  <p>ILCheck il = new ILCheck();</p>

  <p>for(int i = 0; i &lt; cb.length; i++) {</p>

  <p>cb[i].addItemListener(il);</p>

  <p>add(cb[i]);</p>

  <p>}</p>

  <p>cb4.addItemListener(new IL4());</p>

  <p>cb5.addItemListener(new IL5());</p>

  <p>cb6.addItemListener(new IL6());</p>

  <p>add(cb4); add(cb5); add(cb6);</p>

  <p>}</p>

  <p>// Checking the source:</p>

  <p>class ILCheck implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>for(int i = 0; i &lt; cb.length; i++) {</p>

  <p>if(e.getSource().equals(cb[i])) {</p>

  <p>t.setText("Check box " + (i + 1));</p>

  <p>return;</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>// vs. an individual class for each item:</p>

  <p>class IL4 implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>t.setText("Radio button four");</p>

  <p>}</p>

  <p>}</p>

  <p>class IL5 implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>t.setText("Radio button five");</p>

  <p>}</p>

  <p>}</p>

  <p>class IL6 implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>t.setText("Radio button six");</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>RadioCheckNew applet = new RadioCheckNew();</p>

  <p>Frame aFrame = new Frame("RadioCheckNew");</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(300,200);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>ILCheck拥有当我们增加或者减少复选框时自动调整的优点。当然，我们对单选钮使用这种方法也同样的好。但是，它仅当我们的逻辑足以普遍的支持这种方法时才会被使用。如果声明一个确定的信号――我们将重复利用独立的接收器类，否则我们将结束一串条件语句。</p>

  <p>4. 下拉列表</p>

  <p>下拉列表在Java 1.1版中当一个选择被改变时同样使用ItemListener去告知我们：</p>

  <p>//: ChoiceNew.java</p>

  <p>// Drop-down lists with Java 1.1</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>import java.applet.*;</p>

  <p>public class ChoiceNew extends Applet {</p>

  <p>String[] description = { "Ebullient", "Obtuse",</p>

  <p>"Recalcitrant", "Brilliant", "Somnescent",</p>

  <p>"Timorous", "Florid", "Putrescent" };</p>

  <p>TextField t = new TextField(100);</p>

  <p>Choice c = new Choice();</p>

  <p>Button b = new Button("Add items");</p>

  <p>int count = 0;</p>

  <p>public void init() {</p>

  <p>t.setEditable(false);</p>

  <p>for(int i = 0; i &lt; 4; i++)</p>

  <p>c.addItem(description[count++]);</p>

  <p>add(t);</p>

  <p>add(c);</p>

  <p>add(b);</p>

  <p>c.addItemListener(new CL());</p>

  <p>b.addActionListener(new BL());</p>

  <p>}</p>

  <p>class CL implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>t.setText("index: " + c.getSelectedIndex()</p>

  <p>+ " " + e.toString());</p>

  <p>}</p>

  <p>}</p>

  <p>class BL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>if(count &lt; description.length)</p>

  <p>c.addItem(description[count++]);</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>ChoiceNew applet = new ChoiceNew();</p>

  <p>Frame aFrame = new Frame("ChoiceNew");</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(750,100);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>这个程序中没什么特别新颖的东西（除了Java 1.1版的UI类里少数几个值得关注的缺陷）。</p>

  <p>5. 列表</p>

  <p>我们消除了Java 1.0中List设计的一个缺陷，就是List不能像我们希望的那样工作：它会与单击在一个列表元素上发生冲突。</p>

  <p>//: ListNew.java</p>

  <p>// Java 1.1 Lists are easier to use</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>import java.applet.*;</p>

  <p>public class ListNew extends Applet {</p>

  <p>String[] flavors = { "Chocolate", "Strawberry",</p>

  <p>"Vanilla Fudge Swirl", "Mint Chip",</p>

  <p>"Mocha Almond Fudge", "Rum Raisin",</p>

  <p>"Praline Cream", "Mud Pie" };</p>

  <p>// Show 6 items, allow multiple selection:</p>

  <p>List lst = new List(6, true);</p>

  <p>TextArea t = new TextArea(flavors.length, 30);</p>

  <p>Button b = new Button("test");</p>

  <p>int count = 0;</p>

  <p>public void init() {</p>

  <p>t.setEditable(false);</p>

  <p>for(int i = 0; i &lt; 4; i++)</p>

  <p>lst.addItem(flavors[count++]);</p>

  <p>add(t);</p>

  <p>add(lst);</p>

  <p>add(b);</p>

  <p>lst.addItemListener(new LL());</p>

  <p>b.addActionListener(new BL());</p>

  <p>}</p>

  <p>class LL implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>t.setText("");</p>

  <p>String[] items = lst.getSelectedItems();</p>

  <p>for(int i = 0; i &lt; items.length; i++)</p>

  <p>t.append(items[i] + "\n");</p>

  <p>}</p>

  <p>}</p>

  <p>class BL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>if(count &lt; flavors.length)</p>

  <p>lst.addItem(flavors[count++], 0);</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>ListNew applet = new ListNew();</p>

  <p>Frame aFrame = new Frame("ListNew");</p>

  <p>aFrame.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>aFrame.add(applet, BorderLayout.CENTER);</p>

  <p>aFrame.setSize(300,200);</p>

  <p>applet.init();</p>

  <p>applet.start();</p>

  <p>aFrame.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>我们可以注意到在列表项中无需特别的逻辑需要去支持一个单击动作。我们正好像我们在其它地方所做的那样附加上一个接收器。</p>

  <p>6. 菜单</p>

  <p>为菜单处理事件看起来受益于Java 1.1版的事件模型，但Java生成菜单的方法常常麻烦并且需要一些手工编写代码。生成菜单的正确方法看起来像资源而不是一些代码。请牢牢记住编程工具会广泛地为我们处理创建的菜单，因此这可以减少我们的痛苦（只要它们会同样处理维护任务！）。另外，我们将发现菜单不支持并且将导致混乱的事件：菜单项使用ActionListeners（动作接收器），但复选框菜单项使用ItemListeners（项目接收器）。菜单对象同样能支持ActionListeners（动作接收器），但通常不那么有用。一般来说，我们会附加接收器到每个菜单项或复选框菜单项，但下面的例子（对先前例子的修改）演示了一个联合捕捉多个菜单组件到一个单独的接收器类的方法。正像我们将看到的，它或许不值得为这而激烈地争论。</p>

  <p>//: MenuNew.java</p>

  <p>// Menus in Java 1.1</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>public class MenuNew extends Frame {</p>

  <p>String[] flavors = { "Chocolate", "Strawberry",</p>

  <p>"Vanilla Fudge Swirl", "Mint Chip",</p>

  <p>"Mocha Almond Fudge", "Rum Raisin",</p>

  <p>"Praline Cream", "Mud Pie" };</p>

  <p>TextField t = new TextField("No flavor", 30);</p>

  <p>MenuBar mb1 = new MenuBar();</p>

  <p>Menu f = new Menu("File");</p>

  <p>Menu m = new Menu("Flavors");</p>

  <p>Menu s = new Menu("Safety");</p>

  <p>// Alternative approach:</p>

  <p>CheckboxMenuItem[] safety = {</p>

  <p>new CheckboxMenuItem("Guard"),</p>

  <p>new CheckboxMenuItem("Hide")</p>

  <p>};</p>

  <p>MenuItem[] file = {</p>

  <p>// No menu shortcut:</p>

  <p>new MenuItem("Open"),</p>

  <p>// Adding a menu shortcut is very simple:</p>

  <p>new MenuItem("Exit",</p>

  <p>new MenuShortcut(KeyEvent.VK_E))</p>

  <p>};</p>

  <p>// A second menu bar to swap to:</p>

  <p>MenuBar mb2 = new MenuBar();</p>

  <p>Menu fooBar = new Menu("fooBar");</p>

  <p>MenuItem[] other = {</p>

  <p>new MenuItem("Foo"),</p>

  <p>new MenuItem("Bar"),</p>

  <p>new MenuItem("Baz"),</p>

  <p>};</p>

  <p>// Initialization code:</p>

  <p>{</p>

  <p>ML ml = new ML();</p>

  <p>CMIL cmil = new CMIL();</p>

  <p>safety[0].setActionCommand("Guard");</p>

  <p>safety[0].addItemListener(cmil);</p>

  <p>safety[1].setActionCommand("Hide");</p>

  <p>safety[1].addItemListener(cmil);</p>

  <p>file[0].setActionCommand("Open");</p>

  <p>file[0].addActionListener(ml);</p>

  <p>file[1].setActionCommand("Exit");</p>

  <p>file[1].addActionListener(ml);</p>

  <p>other[0].addActionListener(new FooL());</p>

  <p>other[1].addActionListener(new BarL());</p>

  <p>other[2].addActionListener(new BazL());</p>

  <p>}</p>

  <p>Button b = new Button("Swap Menus");</p>

  <p>public MenuNew() {</p>

  <p>FL fl = new FL();</p>

  <p>for(int i = 0; i &lt; flavors.length; i++) {</p>

  <p>MenuItem mi = new MenuItem(flavors[i]);</p>

  <p>mi.addActionListener(fl);</p>

  <p>m.add(mi);</p>

  <p>// Add separators at intervals:</p>

  <p>if((i+1) % 3 == 0)</p>

  <p>m.addSeparator();</p>

  <p>}</p>

  <p>for(int i = 0; i &lt; safety.length; i++)</p>

  <p>s.add(safety[i]);</p>

  <p>f.add(s);</p>

  <p>for(int i = 0; i &lt; file.length; i++)</p>

  <p>f.add(file[i]);</p>

  <p>mb1.add(f);</p>

  <p>mb1.add(m);</p>

  <p>setMenuBar(mb1);</p>

  <p>t.setEditable(false);</p>

  <p>add(t, BorderLayout.CENTER);</p>

  <p>// Set up the system for swapping menus:</p>

  <p>b.addActionListener(new BL());</p>

  <p>add(b, BorderLayout.NORTH);</p>

  <p>for(int i = 0; i &lt; other.length; i++)</p>

  <p>fooBar.add(other[i]);</p>

  <p>mb2.add(fooBar);</p>

  <p>}</p>

  <p>class BL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>MenuBar m = getMenuBar();</p>

  <p>if(m == mb1) setMenuBar(mb2);</p>

  <p>else if (m == mb2) setMenuBar(mb1);</p>

  <p>}</p>

  <p>}</p>

  <p>class ML implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>MenuItem target = (MenuItem)e.getSource();</p>

  <p>String actionCommand =</p>

  <p>target.getActionCommand();</p>

  <p>if(actionCommand.equals("Open")) {</p>

  <p>String s = t.getText();</p>

  <p>boolean chosen = false;</p>

  <p>for(int i = 0; i &lt; flavors.length; i++)</p>

  <p>if(s.equals(flavors[i])) chosen = true;</p>

  <p>if(!chosen)</p>

  <p>t.setText("Choose a flavor first!");</p>

  <p>else</p>

  <p>t.setText("Opening "+ s +". Mmm, mm!");</p>

  <p>} else if(actionCommand.equals("Exit")) {</p>

  <p>dispatchEvent(</p>

  <p>new WindowEvent(MenuNew.this,</p>

  <p>WindowEvent.WINDOW_CLOSING));</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>class FL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>MenuItem target = (MenuItem)e.getSource();</p>

  <p>t.setText(target.getLabel());</p>

  <p>}</p>

  <p>}</p>

  <p>// Alternatively, you can create a different</p>

  <p>// class for each different MenuItem. Then you</p>

  <p>// Don't have to figure out which one it is:</p>

  <p>class FooL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t.setText("Foo selected");</p>

  <p>}</p>

  <p>}</p>

  <p>class BarL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t.setText("Bar selected");</p>

  <p>}</p>

  <p>}</p>

  <p>class BazL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>t.setText("Baz selected");</p>

  <p>}</p>

  <p>}</p>

  <p>class CMIL implements ItemListener {</p>

  <p>public void itemStateChanged(ItemEvent e) {</p>

  <p>CheckboxMenuItem target =</p>

  <p>(CheckboxMenuItem)e.getSource();</p>

  <p>String actionCommand =</p>

  <p>target.getActionCommand();</p>

  <p>if(actionCommand.equals("Guard"))</p>

  <p>t.setText("Guard the Ice Cream! " +</p>

  <p>"Guarding is " + target.getState());</p>

  <p>else if(actionCommand.equals("Hide"))</p>

  <p>t.setText("Hide the Ice Cream! " +</p>

  <p>"Is it cold? " + target.getState());</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>MenuNew f = new MenuNew();</p>

  <p>f.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>f.setSize(300,200);</p>

  <p>f.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>在我们开始初始化节（由注解“Initialization code:”后的右大括号指明）的前面部分的代码同先前（Java 1.0版）版本相同。这里我们可以注意到项目接收器和动作接收器被附加在不同的菜单组件上。</p>

  <p>Java 1.1支持“菜单快捷键”，因此我们可以选择一个菜单项目利用键盘替代鼠标。这十分的简单；我们只要使用过载菜单项构建器设置第二个自变量为一个MenuShortcut（菜单快捷键事件）对象即可。菜单快捷键构建器设置重要的方法，当它按下时不可思议地显示在菜单项上。上面的例子增加了Control-E到“Exit”</p>

  <p>菜单项中。</p>

  <p>我们同样会注意setActionCommand()的使用。这看似一点陌生因为在各种情况下“action command”完全同菜单组件上的标签一样。为什么不正好使用标签代替可选择的字符串呢？这个难题是国际化的。如果我们重新用其它语言写这个程序，我们只需要改变菜单中的标签，并不审查代码中可能包含新错误的所有逻辑。因此使这对检查文字字符串联合菜单组件的代码而言变得简单容易，当菜单标签能改变时“动作指令”可以不作任何的改变。所有这些代码同“动作指令”一同工作，因此它不会受改变菜单标签的影响。注意在这个程序中，不是所有的菜单组件都被它们的动作指令所审查，因此这些组件都没有它们的动作指令集。</p>

  <p>大多数的构建器同前面的一样，将几个调用的异常增加到接收器中。大量的工作发生在接收器里。在前面例子的BL中，菜单交替发生。在ML中，“寻找ring”方法被作为动作事件（ActionEvent）的资源并对它进行造型送入菜单项，然后得到动作指令字符串，再通过它去贯穿串联组，当然条件是对它进行声明。这些大多数同前面的一样，但请注意如果“Exit”被选中，通过进入封装类对象的句柄（MenuNew.this）并创建一个WINDOW_CLOSING事件，一个新的窗口事件就被创建了。新的事件被分配到封装类对象的dispatchEvent()方法，然后结束调用windowsClosing()内部帧的窗口接收器（这个接收器作为一个内部类被创建在main()里），似乎这是“正常”产生消息的方法。通过这种机制，我们可以在任何情况下迅速处理任何的信息，因此，它非常的强大。</p>

  <p>FL接收器是很简单尽管它能处理特殊菜单的所有不同的特色。如果我们的逻辑十分的简单明了，这种方法对我们就很有用处，但通常，我们使用这种方法时需要与FooL，BarL和BazL一道使用，它们每个都附加到一个单独的菜单组件上，因此必然无需测试逻辑，并且使我们正确地辨识出谁调用了接收器。这种方法产生了大量的类，内部代码趋向于变得小巧和处理起来简单、安全。</p>

  <p>7. 对话框</p>

  <p>在这个例子里直接重写了早期的ToeTest.java程序。在这个新的版本里，任何事件都被安放进一个内部类中。虽然这完全消除了需要记录产生的任何类的麻烦，作为ToeTest.java的一个例子，它能使内部类的概念变得不那遥远。在这点，内嵌类被嵌套达四层之深！我们需要的这种设计决定了内部类的优点是否值得增加更加复杂的事物。另外，当我们创建一个非静态的内部类时，我们将捆绑非静态类到它周围的类上。有时，单独的类可以更容易地被复用。</p>

  <p>//: ToeTestNew.java</p>

  <p>// Demonstration of dialog boxes</p>

  <p>// and creating your own components</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>public class ToeTestNew extends Frame {</p>

  <p>TextField rows = new TextField("3");</p>

  <p>TextField cols = new TextField("3");</p>

  <p>public ToeTestNew() {</p>

  <p>setTitle("Toe Test");</p>

  <p>Panel p = new Panel();</p>

  <p>p.setLayout(new GridLayout(2,2));</p>

  <p>p.add(new Label("Rows", Label.CENTER));</p>

  <p>p.add(rows);</p>

  <p>p.add(new Label("Columns", Label.CENTER));</p>

  <p>p.add(cols);</p>

  <p>add(p, BorderLayout.NORTH);</p>

  <p>Button b = new Button("go");</p>

  <p>b.addActionListener(new BL());</p>

  <p>add(b, BorderLayout.SOUTH);</p>

  <p>}</p>

  <p>static final int BLANK = 0;</p>

  <p>static final int XX = 1;</p>

  <p>static final int OO = 2;</p>

  <p>class ToeDialog extends Dialog {</p>

  <p>// w = number of cells wide</p>

  <p>// h = number of cells high</p>

  <p>int turn = XX; // Start with x's turn</p>

  <p>public ToeDialog(int w, int h) {</p>

  <p>super(ToeTestNew.this,</p>

  <p>"The game itself", false);</p>

  <p>setLayout(new GridLayout(w, h));</p>

  <p>for(int i = 0; i &lt; w * h; i++)</p>

  <p>add(new ToeButton());</p>

  <p>setSize(w * 50, h * 50);</p>

  <p>addWindowListener(new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e){</p>

  <p>dispose();</p>

  <p>}</p>

  <p>});</p>

  <p>}</p>

  <p>class ToeButton extends Canvas {</p>

  <p>int state = BLANK;</p>

  <p>ToeButton() {</p>

  <p>addMouseListener(new ML());</p>

  <p>}</p>

  <p>public void paint(Graphics g) {</p>

  <p>int x1 = 0;</p>

  <p>int y1 = 0;</p>

  <p>int x2 = getSize().width - 1;</p>

  <p>int y2 = getSize().height - 1;</p>

  <p>g.drawRect(x1, y1, x2, y2);</p>

  <p>x1 = x2/4;</p>

  <p>y1 = y2/4;</p>

  <p>int wide = x2/2;</p>

  <p>int high = y2/2;</p>

  <p>if(state == XX) {</p>

  <p>g.drawLine(x1, y1,</p>

  <p>x1 + wide, y1 + high);</p>

  <p>g.drawLine(x1, y1 + high,</p>

  <p>x1 + wide, y1);</p>

  <p>}</p>

  <p>if(state == OO) {</p>

  <p>g.drawOval(x1, y1,</p>

  <p>x1 + wide/2, y1 + high/2);</p>

  <p>}</p>

  <p>}</p>

  <p>class ML extends MouseAdapter {</p>

  <p>public void mousePressed(MouseEvent e) {</p>

  <p>if(state == BLANK) {</p>

  <p>state = turn;</p>

  <p>turn = (turn == XX ? OO : XX);</p>

  <p>}</p>

  <p>else</p>

  <p>state = (state == XX ? OO : XX);</p>

  <p>repaint();</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>class BL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>Dialog d = new ToeDialog(</p>

  <p>Integer.parseInt(rows.getText()),</p>

  <p>Integer.parseInt(cols.getText()));</p>

  <p>d.show();</p>

  <p>}</p>

  <p>}</p>

  <p>public static void main(String[] args) {</p>

  <p>Frame f = new ToeTestNew();</p>

  <p>f.addWindowListener(</p>

  <p>new WindowAdapter() {</p>

  <p>public void windowClosing(WindowEvent e) {</p>

  <p>System.exit(0);</p>

  <p>}</p>

  <p>});</p>

  <p>f.setSize(200,100);</p>

  <p>f.setVisible(true);</p>

  <p>}</p>

  <p>} ///:~</p>

  <p>由于“静态”的东西只能位于类的外部一级，所以内部类不可能拥有静态数据或者静态内部类。</p>

  <p>8. 文件对话框</p>

  <p>这个例子是直接用新事件模型对FileDialogTest.java修改而来。</p>

  <p>//: FileDialogNew.java</p>

  <p>// Demonstration of File dialog boxes</p>

  <p>import java.awt.*;</p>

  <p>import java.awt.event.*;</p>

  <p>public class FileDialogNew extends Frame {</p>

  <p>TextField filename = new TextField();</p>

  <p>TextField directory = new TextField();</p>

  <p>Button open = new Button("Open");</p>

  <p>Button save = new Button("Save");</p>

  <p>public FileDialogNew() {</p>

  <p>setTitle("File Dialog Test");</p>

  <p>Panel p = new Panel();</p>

  <p>p.setLayout(new FlowLayout());</p>

  <p>open.addActionListener(new OpenL());</p>

  <p>p.add(open);</p>

  <p>save.addActionListener(new SaveL());</p>

  <p>p.add(save);</p>

  <p>add(p, BorderLayout.SOUTH);</p>

  <p>directory.setEditable(false);</p>

  <p>filename.setEditable(false);</p>

  <p>p = new Panel();</p>

  <p>p.setLayout(new GridLayout(2,1));</p>

  <p>p.add(filename);</p>

  <p>p.add(directory);</p>

  <p>add(p, BorderLayout.NORTH);</p>

  <p>}</p>

  <p>class OpenL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>// Two arguments, defaults to open file:</p>

  <p>FileDialog d = new FileDialog(</p>

  <p>FileDialogNew.this,</p>

  <p>"What file do you want to open?");</p>

  <p>d.setFile("*.java");</p>

  <p>d.setDirectory("."); // Current directory</p>

  <p>d.show();</p>

  <p>String yourFile = "*.*";</p>

  <p>if((yourFile = d.getFile()) != null) {</p>

  <p>filename.setText(yourFile);</p>

  <p>directory.setText(d.getDirectory());</p>

  <p>} else {</p>

  <p>filename.setText("You pressed cancel");</p>

  <p>directory.setText("");</p>

  <p>}</p>

  <p>}</p>

  <p>}</p>

  <p>class SaveL implements ActionListener {</p>

  <p>public void actionPerformed(ActionEvent e) {</p>

  <p>FileDialog d = new FileDialog(</p>

  <p>FileDialogNew.this,</p>

  <p>"What file do you want to save?",</p>

  <p>FileDialog.SAVE);</p>

  <p>d.setFile("*.java");</p>

  <p>d.setDirectory(".");</p>

  <p>d.show();</p>

  <p>String saveFile;</p>

  <p>if((</p>

  <div class="mbppagebreak"></div>
</body>
</html>
